package com.michaelbulava.TFS.vcs.internal.TFSFiles;

import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.michaelbulava.TFS.common.item.ServerItemPath;
import com.michaelbulava.TFS.vcs.TFSVcs;
import com.michaelbulava.TFS.vcs.utils.TFSFileUtil;
import com.microsoft.tfs.core.clients.versioncontrol.path.ServerPath;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.*;
import com.microsoft.tfs.util.Check;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.nio.charset.Charset;

/**
 * Created by MichaelA on 12/22/2015.
 */
public class TFSFilePath implements FilePath {

    private File localFile;
    private ExtendedItem extendedItem;
    private final Workspace workspace;

    public TFSFilePath(Workspace workspace, ExtendedItem extendedItem){
        Check.notNull(workspace, "workspace");
        Check.notNull(extendedItem, "extendedItem");

        this.workspace = workspace;
        this.extendedItem = extendedItem;
        initializeFromExtendedItem();
    }

//    public TFSFilePath(VirtualFile virtualFile){
//        Check.notNull(virtualFile, "virtualFile");
//        TFSVcs.
//    }



    private void initializeFromExtendedItem(){
        String filePath = extendedItem.getLocalItem();
        if (!StringUtil.isNotEmpty(filePath)){
            //If the filePath it null the file most likely doesn't exist locally
            //So let TFS translate from Server to local path
            PathTranslation translatedPath = workspace
                    .translateServerPathToLocalPath(extendedItem.getTargetServerItem());
            filePath = translatedPath.getTranslatedPath();
        }

        localFile = new File(filePath);
    }

    /**
     * @return a virtual file that corresponds to this path, or null if the virtual file is no more valid.
     */
    @Nullable
    @Override
    public VirtualFile getVirtualFile() {
        return LocalFileSystem.getInstance().findFileByIoFile(localFile);
    }

    /**
     * @return the virtual file that corresponds to the parent file path, or null if the virtual file is no more valid.
     */
    @Nullable
    @Override
    public VirtualFile getVirtualFileParent() {
        if (localFile.exists())
            return getVirtualFile().getParent();
        else
            return LocalFileSystem.getInstance().findFileByIoFile(localFile.getParentFile());
    }

    /**
     * @return the {@link File} that corresponds to the path. The path might be non-existent or not local.
     * @see #isNonLocal()
     */
    @NotNull
    @Override
    public File getIOFile() {
        return localFile;
    }

    /**
     * @return the file name (without directory component)
     */
    @NotNull
    @Override
    public String getName() {
        return localFile.getName();
    }

    /**
     * @return the path to the file in the format suitable for displaying in the UI,
     * e.g. for local file it is the path to this file with system separators.
     */
    @Override
    public String getPresentableUrl() {
        return localFile.getPath();
    }

    /**
     * @deprecated to remove in IDEA 16.
     * Use {@link FileDocumentManager#getDocument(VirtualFile)} directly.
     */
    @Nullable
    @Override
    public Document getDocument() {
        return FileDocumentManager.getInstance().getDocument(getVirtualFile());
    }

    @NotNull
    @Override
    public Charset getCharset() {
        return null;
    }

    /**
     * @param project
     * @return the character set, considering the project settings and the virtual file corresponding to this FilePath (if it exists).
     */
    @NotNull
    @Override
    public Charset getCharset(Project project) {
        return null;
    }

    /**
     * @return the type of the file.
     */
    @NotNull
    @Override
    public FileType getFileType() {
        return null;
    }

    /**
     * @deprecated to remove in IDEA 16.
     * Use {@code com.intellij.openapi.vfs.VfsUtil#findFileByPath} or {@code com.intellij.openapi.vfs.LocalFileSystem#findFileByPath} instead.
     */
    @Override
    public void refresh() {
        ExtendedItem[] items = workspace.getExtendedItems(extendedItem.getTargetServerItem(), DeletedState.ANY,
                ItemType.ANY);
        if (items.length == 1)
            this.extendedItem = items[0];
        else
            throw new RuntimeException(String.format("Expected to locate 1 parent item and found %d", items.length));
    }

    /**
     * @deprecated to remove in IDEA 16.
     * Use {@code com.intellij.openapi.vfs.LocalFileSystem#refreshAndFindFileByPath} instead.
     */
    @Override
    public void hardRefresh() {
        refresh();
    }

    /**
     * @return the path to the file represented by this file path in the system-independent format.
     */
    @NotNull
    @Override
    public String getPath() {
        if (localFile.exists())
            return localFile.getPath();
        else
            return extendedItem.getTargetServerItem();
    }

    /**
     * @return true if the path represents the directory
     */
    @Override
    public boolean isDirectory() {
        return extendedItem.getItemType() == ItemType.FOLDER;
    }

    /**
     * Check if the provided file is an ancestor of the current file.
     *
     * @param parent a possible parent
     * @param strict if false, the method also returns true if files are equal
     * @return true if {@code this} file is ancestor of the {@code parent}.
     */
    @Override
    public boolean isUnder(@NotNull FilePath parent, boolean strict) {
        if (parent instanceof  TFSFilePath){
            ServerPath.isChild(((TFSFilePath)parent).getExtendedItem().getTargetServerItem(),
                    getExtendedItem().getTargetServerItem());
        }

        return false;
    }

    /**
     * @return the parent path or null if there is no parent of this file.
     */
    @Nullable
    @Override
    public FilePath getParentPath() {
        ExtendedItem[] items = workspace.getExtendedItems(ServerPath.getParent(extendedItem.getTargetServerItem()),
                DeletedState.ANY, ItemType.ANY);
        if (items.length == 1)
            return new TFSFilePath(workspace, items[0]);
        else
            throw new RuntimeException(String.format("Expected to locate 1 parent item and found %d", items.length));
    }

    /**
     * @return true if the path does not represents a file in the local file system
     */
    @Override
    public boolean isNonLocal() {
        return !localFile.exists();
    }



    public ExtendedItem getExtendedItem(){
        return this.extendedItem;
    }
}
